package com.xgk.boot.module.core.job;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.util.concurrent.RateLimiter;
import com.xgk.boot.framework.common.util.date.DateUtils;
import com.xgk.boot.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.xgk.boot.module.core.dal.dto.TruckOrderDto;
import com.xgk.boot.module.core.dal.entity.truck.TruckOrdersDO;
import com.xgk.boot.module.core.enums.biz.OrderStatusEnum;
import com.xgk.boot.module.core.logistics.service.TruckOrderCommonService;
import com.xgk.boot.module.core.service.truck.TruckOrdersServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 订单物流信息获取定时任务
 * 1、只针对物流状态 ：运输中的
 * 2、针对最近更新时间是3小时以前的
 * 3、定时任务周期每6小时执行一次，
 * 4、提供特殊运维触发刷新接口
 * 5、日志记录刷新量并限制刷新频率
 */
@Slf4j
@Component
public class OrderTrackJob {

    @Resource
    private TruckOrdersServiceImpl truckOrdersService;
    @Resource
    private TruckOrderCommonService truckOrderCommonService;

    // 每秒允许 10 个请求
    private final RateLimiter rateLimiter = RateLimiter.create(10.0);

    @Scheduled(initialDelay = 2*60, fixedDelay = 8*60*60, timeUnit= TimeUnit.SECONDS)
    public void scheduleRefreshTracking() {
        log.info("schedule job refresh order info (status, tracking, bol)");
        LambdaQueryWrapperX<TruckOrdersDO> ordersWrapperX = new LambdaQueryWrapperX<>();
        ordersWrapperX.in(TruckOrdersDO::getOrderStatus, OrderStatusEnum.PRE_TRANSIT.getValue(), OrderStatusEnum.IN_TRANSIT.getValue());
        //3小时以前的时间
        Instant instant = DateUtils.hoursAgoInstantUTC(3l);
        ordersWrapperX.in(TruckOrdersDO::getOrderStatus, Arrays.asList(OrderStatusEnum.FORECAST,OrderStatusEnum.PRE_TRANSIT,OrderStatusEnum.IN_TRANSIT));
        ordersWrapperX.le(TruckOrdersDO::getSyncCount, 100);
//        ordersWrapperX.le(TruckOrdersDO::getUpdateTime, instant);
        ordersWrapperX.orderByDesc(TruckOrdersDO::getCreateTime);
        ordersWrapperX.select(
                TruckOrdersDO::getOrderId,
                TruckOrdersDO::getOrderCode,
                TruckOrdersDO::getCustomerCode,
                TruckOrdersDO::getProductCode,
                TruckOrdersDO::getSpCode,
                TruckOrdersDO::getOrderStatus,
                TruckOrdersDO::getCurrencyCode,
                TruckOrdersDO::getTrackingNumber);
        int pageSize = 100;
        int currentPage = 1;
        int total = 0;
        while (true) {
            Page<TruckOrdersDO> page = new Page<>(currentPage, pageSize);
            page.setSearchCount(false);
            Page<TruckOrdersDO> pageRes = truckOrdersService.page(page, ordersWrapperX);
            if (pageRes == null) {
                break;
            }
            List<TruckOrdersDO> records = pageRes.getRecords();
            total = total+records.size();
            log.info("当前页码：{}，当前页记录数：{}，总记录数：{}", currentPage,  records.size(),pageRes.getPages(),total);
            if (records.isEmpty()) {
                break;
            }
            for (TruckOrdersDO record : records) {
                limitedEndpoint();
                try {
                    String orderCode = record.getOrderCode();
                    TruckOrderDto truckOrderDto = truckOrdersService.factoryOrderDto(orderCode);
                    truckOrderCommonService.getOrderDetail(truckOrderDto);
                    truckOrderCommonService.getOrderTracking(truckOrderDto);
                    truckOrderCommonService.getOrUpdateOrderBol(truckOrderDto);
                }catch (Exception e){
                    log.error("刷新订单物流信息失败", e);
                }
            }
            if (records.size() < pageSize) {
                break;
            }
            currentPage = currentPage+1;
        }

        log.info("刷新订单物流信息完成,总记录数：{}", total);
    }

    //限流控制
    private void limitedEndpoint() {
        try {
            while (true) {
                if (rateLimiter.tryAcquire()) { // 尝试获取令牌
                    return;
                }
                log.warn("ratelimter ,please wait..");
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }


}
